package io.github.jsp.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

/**
 * 基于本地IP的雪花算法ID生成器
 * 
 * 雪花算法ID结构（64位）：
 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
 * 1位符号位 + 41位时间戳 + 5位数据中心ID + 5位机器ID + 12位序列号
 */

public class SnowflakeIdGenerator {

    static Logger log = LoggerFactory.getLogger(SnowflakeIdGenerator.class);

    // 起始时间戳（2023-01-01 00:00:00 UTC）
    private static final long START_TIMESTAMP = 1672531200000L;
    
    // 各部分位数
    private static final long SEQUENCE_BITS = 12L;
    private static final long MACHINE_ID_BITS = 5L;
    private static final long DATACENTER_ID_BITS = 5L;
    
    // 最大值
    private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1;
    private static final long MAX_MACHINE_ID = (1L << MACHINE_ID_BITS) - 1;
    private static final long MAX_DATACENTER_ID = (1L << DATACENTER_ID_BITS) - 1;
    
    // 位移量
    private static final long MACHINE_ID_SHIFT = SEQUENCE_BITS;
    private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;
    private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATACENTER_ID_BITS;
    
    // 实例变量
    private final long datacenterId;
    private final long machineId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;
    
    // 单例实例
    private static volatile SnowflakeIdGenerator instance;
    private static final Object lock = new Object();
    
    /**
     * 私有构造函数
     */
    private SnowflakeIdGenerator() {
        // 基于本地IP生成数据中心ID和机器ID
        String localIp = getLocalIpAddress();
        log.info("Local IP address: {}", localIp);
        
        this.datacenterId = generateDatacenterId(localIp);
        this.machineId = generateMachineId(localIp);
        
        log.info("Snowflake ID Generator initialized - DataCenter ID: {}, Machine ID: {}", 
                datacenterId, machineId);
    }
    
    /**
     * 获取单例实例
     */
    public static SnowflakeIdGenerator getInstance() {
        if (instance == null) {
            synchronized (lock) {
                if (instance == null) {
                    instance = new SnowflakeIdGenerator();
                }
            }
        }
        return instance;
    }
    
    /**
     * 生成下一个ID
     */
    public synchronized long nextId() {
        long currentTimestamp = System.currentTimeMillis();
        
        // 检查时钟回退
        if (currentTimestamp < lastTimestamp) {
            long offset = lastTimestamp - currentTimestamp;
            if (offset > 5) {
                throw new RuntimeException(String.format(
                    "Clock moved backwards. Refusing to generate id for %d milliseconds", offset));
            }
            
            // 如果时钟回退时间较短，等待追上
            try {
                Thread.sleep(offset << 1);
                currentTimestamp = System.currentTimeMillis();
                if (currentTimestamp < lastTimestamp) {
                    throw new RuntimeException(String.format(
                        "Clock moved backwards. Refusing to generate id for %d milliseconds", 
                        lastTimestamp - currentTimestamp));
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Interrupted while waiting for clock adjustment", e);
            }
        }
        
        // 同一毫秒内生成多个ID
        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                // 序列号用完，等待下一毫秒
                currentTimestamp = waitForNextMillis(currentTimestamp);
            }
        } else {
            // 新的毫秒，重置序列号
            sequence = 0L;
        }
        
        lastTimestamp = currentTimestamp;
        
        // 组装ID
        return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
                | (datacenterId << DATACENTER_ID_SHIFT)
                | (machineId << MACHINE_ID_SHIFT)
                | sequence;
    }
    
    /**
     * 等待下一毫秒
     */
    private long waitForNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
    
    /**
     * 获取本地IP地址
     */
    private String getLocalIpAddress() {
        try {
            // 首先尝试获取非回环地址
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface networkInterface = interfaces.nextElement();
                
                // 跳过回环接口和未启用的接口
                if (networkInterface.isLoopback() || !networkInterface.isUp()) {
                    continue;
                }
                
                Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress address = addresses.nextElement();
                    
                    // 跳过回环地址和IPv6地址
                    if (address.isLoopbackAddress() || address.getHostAddress().contains(":")) {
                        continue;
                    }
                    
                    String ip = address.getHostAddress();
                    log.debug("Found IP address: {}", ip);
                    return ip;
                }
            }
            
            // 如果没有找到合适的IP，使用localhost
            return InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            log.warn("Failed to get local IP address, using default", e);
            return "127.0.0.1";
        }
    }
    
    /**
     * 基于IP地址生成数据中心ID
     */
    private long generateDatacenterId(String ip) {
        try {
            String[] parts = ip.split("\\.");
            if (parts.length == 4) {
                // 使用IP的第三段生成数据中心ID
                long id = (Long.parseLong(parts[2]) + Long.parseLong(parts[3])) & MAX_DATACENTER_ID;
                log.debug("Generated datacenter ID: {} from IP: {}", id, ip);
                return id;
            }
        } catch (Exception e) {
            log.warn("Failed to generate datacenter ID from IP: {}", ip, e);
        }
        
        // 默认数据中心ID
        return 1L;
    }
    
    /**
     * 基于IP地址生成机器ID
     */
    private long generateMachineId(String ip) {
        try {
            String[] parts = ip.split("\\.");
            if (parts.length == 4) {
                // 使用IP的最后一段生成机器ID
                long id = Long.parseLong(parts[3]) & MAX_MACHINE_ID;
                log.debug("Generated machine ID: {} from IP: {}", id, ip);
                return id;
            }
        } catch (Exception e) {
            log.warn("Failed to generate machine ID from IP: {}", ip, e);
        }
        
        // 默认机器ID
        return 1L;
    }
    
    /**
     * 解析ID各部分信息
     */
    public SnowflakeIdInfo parseId(long id) {
        long timestamp = (id >> TIMESTAMP_SHIFT) + START_TIMESTAMP;
        long datacenterId = (id >> DATACENTER_ID_SHIFT) & MAX_DATACENTER_ID;
        long machineId = (id >> MACHINE_ID_SHIFT) & MAX_MACHINE_ID;
        long sequence = id & MAX_SEQUENCE;
        
        return new SnowflakeIdInfo(id, timestamp, datacenterId, machineId, sequence);
    }
    
    /**
     * 获取当前配置信息
     */
    public String getInfo() {
        return String.format("SnowflakeIdGenerator[datacenterId=%d, machineId=%d, sequence=%d, lastTimestamp=%d]",
                datacenterId, machineId, sequence, lastTimestamp);
    }
    
    // Getters
    public long getDatacenterId() {
        return datacenterId;
    }
    
    public long getMachineId() {
        return machineId;
    }
    
    /**
     * ID信息类
     */
    public static class SnowflakeIdInfo {
        private final long id;
        private final long timestamp;
        private final long datacenterId;
        private final long machineId;
        private final long sequence;
        
        public SnowflakeIdInfo(long id, long timestamp, long datacenterId, long machineId, long sequence) {
            this.id = id;
            this.timestamp = timestamp;
            this.datacenterId = datacenterId;
            this.machineId = machineId;
            this.sequence = sequence;
        }
        
        // Getters
        public long getId() { return id; }
        public long getTimestamp() { return timestamp; }
        public long getDatacenterId() { return datacenterId; }
        public long getMachineId() { return machineId; }
        public long getSequence() { return sequence; }
        
        @Override
        public String toString() {
            return String.format("SnowflakeIdInfo{id=%d, timestamp=%d, datacenterId=%d, machineId=%d, sequence=%d}",
                    id, timestamp, datacenterId, machineId, sequence);
        }
    }
}